//
//  NemoSign.m
//  NemoSDKDemo
//
//  Created by 高超 on 2020/3/13.
//  Copyright © 2020 JackYang. All rights reserved.
//

#import "NemoSign.h"
#import <openssl/sha.h>
#import <CommonCrypto/CommonHMAC.h>

@interface NemoSign ()
{
    NSString *_methodString;
    NSString *_uriString;
    NSString *_bodyString;
    NSString *_entitySign;
    NSString *_sign;
}
@end

@implementation NemoSign

- (NSString *)signUrl:(NSString *)url
           methodType:(NSString *)methodType
               params:(NSString *)params
                token:(NSString *)token
{
    _methodString = [NSString stringWithFormat:@"%@",methodType.uppercaseString];
    
    NSArray *separated_One = [url componentsSeparatedByString:@"?"];
    _uriString = [self findUri:separated_One.firstObject];
    if (separated_One.count > 1) {
        NSMutableDictionary *paramsDic = [NSMutableDictionary dictionary];
        NSArray *params = [separated_One.lastObject componentsSeparatedByString:@"&"];
        for (NSString *string in params) {
            NSArray *keyAndValue = [string componentsSeparatedByString:@"="];
            [paramsDic addEntriesFromDictionary:@{keyAndValue.firstObject:keyAndValue.lastObject}];
        }
        
        _bodyString = [self paramsSerialize:paramsDic];
    }
    
    if (params.length && ![[params substringFromIndex:params.length-2] isEqualToString:@"\0"]) {
        params = [NSString stringWithFormat:@"%@\0",params];
    }
    void *entity = (void *)[params dataUsingEncoding:NSUTF8StringEncoding].bytes;
    _entitySign = [self sha256:entity];
    
    NSString *string = [NSString stringWithFormat:@"%@\n%@\n%@\n%@",_methodString,_uriString,_bodyString,_entitySign];
    _sign = [self hmac_sha256:string token:token];
    
    
    return _sign;
}

- (NSString *)findUri:(NSString *)string {
    NSRange range = [string rangeOfString:@"api/rest/external/"];
    NSString *subString = [string substringWithRange:NSMakeRange(range.location + range.length, string.length - (range.length + range.location))];
    int location = 0;
    for (int i = 0; i < subString.length; i++) {
        char c = [subString characterAtIndex:i];
        if (strncmp(&c, "/", 1) == 0) {
            location = i;
            break;
        }
    }
    return [subString substringWithRange:NSMakeRange(location + 1, subString.length - (location + 1))];
}

- (NSString *)paramsSerialize:(NSDictionary *)params {
    if (params == nil) {
        return  @"";
    }
    
    __block NSMutableString *paramsStr = [NSMutableString string];
    NSArray *keysArr = [params.allKeys sortedArrayUsingSelector:@selector(compare:)];
    [keysArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (idx != keysArr.count - 1) {
            NSString *temp = [NSString stringWithFormat:@"%@=%@&",obj,[params objectForKey:obj]];
            [paramsStr appendString:[temp stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
        }else{
            NSString *temp = [NSString stringWithFormat:@"%@=%@",obj,[params objectForKey:obj]];
            [paramsStr appendString:[temp stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
        }
    }];
    return [NSString stringWithFormat:@"%@",paramsStr];
}

- (NSString *)sha256:(void *)buf{
    char *cstr = (char *)buf;
    
    uint8_t digest[SHA256_DIGEST_LENGTH];
    
    
    char *cs = NULL;
    if (strlen(cstr) > 100) {
        cs = malloc(101 * sizeof(char));
        memcpy(cs, cstr, 100);
        cs[100] = '\0';
    }else{
        cs = malloc((strlen(cstr)+1) * sizeof(char));
        memcpy(cs, cstr, strlen(cstr));
        cs[strlen(cstr)] = '\0';
    }
    
    SHA256((const unsigned char *)cs, strlen(cs), digest);
    free(cs);
    
    NSData *da = [[NSData alloc] initWithBytes:digest length:SHA256_DIGEST_LENGTH];
    
    NSString *output = [da base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    return output;
}

- (NSString *)hmac_sha256:(NSString *)signString token:(NSString *)token{
    const char *cKey  = [token cStringUsingEncoding:NSUTF8StringEncoding];
    const char *cData = [signString cStringUsingEncoding:NSUTF8StringEncoding];
    
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    
    NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
    NSString *output = [HMACData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    
    NSMutableCharacterSet *characterSet = [[NSMutableCharacterSet alloc]init];
    [characterSet formIntersectionWithCharacterSet:[NSCharacterSet URLQueryAllowedCharacterSet]];
    [characterSet addCharactersInString:@"+"];
    
    return [output stringByAddingPercentEncodingWithAllowedCharacters:characterSet.invertedSet];
}

@end
